/************************************************************************************
**  
* @copyright (c) 2015-, Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file     duye_cap_http_service.cpp
* @version     
* @brief      
* @author   
* @date     2013-01-14
* @note 
*
*  1. 2018-01-14 created this file
* 
*/
#include <duye_system.h>
#include <duye_logger.h>
#include <duye_cap_http_service.h>

static const int8* DUYE_LOG_PREFIX = "duye.cap.http.service";

namespace duye {

HttpService::HttpService() : CapDataService("HttpService") {
	TcpService::instance().addListener(this);
}

HttpService::~HttpService() {
	for (HttpListenerMap::iterator iter = m_listenerMap.begin(); iter != m_listenerMap.end(); ++iter) {
		delete iter->second;
	}

	m_listenerMap.clear();
}

bool HttpService::start() {
	startTask();
	return true;
}

bool HttpService::stop() {
	return true;
}

bool HttpService::run() {
	DUYE_INFO("HttpService Start");

	for (;;) {
		DUYE_INFO("HttpService Working");
		System::sleep(10);
	}

	DUYE_INFO("HttpService Exit");

	return true;
}

bool HttpService::addListener(DataServiceListener* listener, const FilterRule* filterRule) {
	HttpListener* httpListener = dynamic_cast<HttpListener*>(listener);
	if (httpListener == NULL) {
		return false;
	}
	
	FilterRule* copyFilterRule = NULL;
	if (filterRule == NULL) {
		m_listenerMap.insert(std::make_pair(httpListener, copyFilterRule));
	} else {
		copyFilterRule = new FilterRule(*filterRule);
		m_listenerMap.insert(std::make_pair(httpListener, copyFilterRule));
	}

	return true;
}

bool HttpService::delListener(DataServiceListener* listener) {
	m_listenerMap.erase(dynamic_cast<HttpListener*>(listener));
	return true;
}

int32 HttpService::onTcpPacket(const PacketReference& pktRef) {
	if (pktRef.isNull()) {
		DUYE_ERROR("pktRef.isNull()");
		return -1;
	}

	return 0;
}

int32 HttpService::onTcpSession(const PacketReference& pktRef, const TcpSession& tcpSession) {
	if (pktRef.isNull()) {
		DUYE_ERROR("pktRef.isNull()");
		return -1;
	}

	if (tcpSession.getSrcPort() != Protocols::instance().getPort(PROTO_HTTP) ||
		tcpSession.getDstPort() != Protocols::instance().getPort(PROTO_HTTP)) {
		return -1;
	}

	DUYE_DEBUG("Protocol type(%d) is %s.\n", 
		PROTO_HTTP, 
		Protocols::instance().getName(PROTO_HTTP).c_str());

	HttpAnalyser* analyser = NULL;
	HttpAnalyserKey key;
	if (pktRef->getSrcIP() == tcpSession.getSrcIp()) {
		key.SetSrcIp(tcpSession.getSrcIp());
		key.SetDstIp(tcpSession.getDstIp());
		key.SetSrcPort(tcpSession.getSrcPort());
		key.SetDstPort(tcpSession.getDstPort());
	} else {
		key.SetDstIp(tcpSession.getSrcIp());
		key.SetSrcIp(tcpSession.getDstIp());
		key.SetDstPort(tcpSession.getSrcPort());
		key.SetSrcPort(tcpSession.getDstPort());
	}
	
	HttpAnalyserMap::iterator iterAnalyser = m_analyserForSession.find(key);
	if (iterAnalyser == m_analyserForSession.end()) {
		analyser = createAnalyser();
		if (!analyser) {
			DUYE_ERROR(" createAnalyser() failed.");
			return -1;
		}

		HttpAnalyserPair pair;
		pair.first = analyser;
		pair.second.m_srcMac.assign((const int8* )tcpSession.getSrcMac());
		pair.second.m_dstMac.assign((const int8* )tcpSession.getDstMac());
		pair.second.m_srcIpPort.first = tcpSession.getSrcIp();
		pair.second.m_srcIpPort.second = tcpSession.getSrcPort();
		pair.second.m_dstIpPort.first = tcpSession.getDstIp();
		pair.second.m_dstIpPort.second = tcpSession.getDstPort();

		std::pair<HttpAnalyserMap::iterator, bool> ret =
			m_analyserForSession.insert(std::make_pair(key, pair));
		iterAnalyser = ret.first;
	}

	analyser = iterAnalyser->second.first;
	HttpAnalyserResult analyserRet;
	if (0 == analyser->analyse(pktRef, tcpSession, analyserRet)) {
		if (analyserRet.m_isComplete) {
			// fix HttpOutput
			HttpOutput& output = iterAnalyser->second.second;
			output.m_url.assign((const int8* )analyserRet.m_url);
			output.m_status.assign((const int8* )analyserRet.m_status);

			if (analyserRet.m_body.data && analyserRet.m_body.len) {
				if (output.m_body.data) {
					free(output.m_body.data);
				}

				output.m_body.data = (uint8* )malloc(analyserRet.m_body.len);
				memcpy(output.m_body.data, analyserRet.m_body.data, analyserRet.m_body.len);
				output.m_body.len = analyserRet.m_body.len;
			}

			HttpAnalyserResult::HeaderPairList::iterator iterheaderPair = analyserRet.m_headerPairList.begin();
			for (; iterheaderPair != analyserRet.m_headerPairList.end(); iterheaderPair++) {
				output.m_headerPairList.push_back(
					std::make_pair(std::string((const int8* )iterheaderPair->first), 
					std::string((const int8* )iterheaderPair->second)));
			}

			// TODO: output ...
			HttpSession* httpSession = NULL;
			HttpOutputReference outputRef(new HttpOutput(output));
			for (HttpListenerMap::iterator iterListener = m_listenerMap.begin(); iterListener != m_listenerMap.end(); ++iterListener) {
				// TODO: fiter !!!!!!!!
				/*if (FilterEngine::instance().filterPkt(pktRef, iterListener->second))
				{*/
					iterListener->first->onHttpPkt(outputRef);
					if (httpSession != NULL) {
						iterListener->first->onHttpSession(outputRef, *httpSession);
					}
				/*}*/
			}
		}
	} else {
		// fail
		DUYE_ERROR(" analyser->analyse() failed.");
		return -1;
	}

	return 0;
}

HttpAnalyser* HttpService::createAnalyser() {
	return new HttpAnalyser();
}

void HttpService::recycleAnalyser(HttpAnalyser* analyser) {
	delete analyser;
}

}
